package com.yugao.fintech.antelope.infra.group.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yugao.fintech.antelope.infra.group.assembly.DataGroupAssembly;
import com.yugao.fintech.antelope.infra.group.mapper.DataGroupMapper;
import com.yugao.fintech.antelope.infra.module.group.model.entity.DataGroup;
import com.yugao.fintech.antelope.base.model.constants.CommonCons;
import com.yugao.fintech.antelope.base.model.constants.TreeCons;
import com.yugao.fintech.antelope.base.model.enums.DataGroupBizTypeEnum;
import com.yugao.fintech.framework.assistant.utils.CollectionUtils;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import com.yugao.fintech.framework.assistant.utils.tree.TreeUtils;
import com.yugao.fintech.framework.mybatisplus.utils.PageUtil;
import com.yugao.fintech.framework.validation.ValidationUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.validation.Validator;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 通用数据组
 */
@Slf4j
@Service
public class DataGroupServiceImpl extends ServiceImpl<DataGroupMapper, DataGroup> implements IService<DataGroup>, DataGroupService {
    @Autowired
    private DataGroupAssembly dataGroupAssembly;
    @Autowired
    private Validator validator;

    @Override
    public IPage<DataGroupResp> pageGroup(DataGroupPageReq req) {
        List<Long> ids = StringUtils.toList(req.getIds(), ",", Long.class);
        // 初始化默认分组
        initDefaultGroup(req.getBizType(), req.getGroupType());

        LocalDateTime beginTime = req.getBeginLocalDateTime();
        LocalDateTime endTime = req.getEndLocalDateTime();
        LambdaQueryWrapper<DataGroup> lqw = DataGroup.lqw()
                .ge(Objects.nonNull(beginTime), DataGroup::getCreatedAt, beginTime)
                .in(CollectionUtils.isNotEmpty(ids), DataGroup::getId, ids)
                .eq(StringUtils.isNotEmpty(req.getGroupType()), DataGroup::getGroupType, req.getGroupType())
                .le(Objects.nonNull(endTime), DataGroup::getCreatedAt, endTime)
                .eq(DataGroup::getBizType, req.getBizType())
                .like(StringUtils.isNotEmpty(req.getName()), DataGroup::getName, req.getName())
                .orderByAsc(DataGroup::getSortNo).orderByDesc(DataGroup::getCreatedAt);
        IPage<DataGroup> pageData = this.page(PageUtil.to(req), lqw);
        return PageUtil.to(pageData, dataGroupAssembly::toDataGroupResp);
    }

    @Override
    public List<DataGroupResp> listGroup(DataGroupListReq req) {
        // 初始化默认分组
        initDefaultGroup(req.getBizType(), req.getGroupType());

        LambdaQueryWrapper<DataGroup> lqw = DataGroup.lqw()
                .eq(DataGroup::getBizType, req.getBizType())
                .in(CollectionUtils.isNotEmpty(req.getIds()), DataGroup::getId, req.getIds())
                .eq(StringUtils.isNotEmpty(req.getGroupType()), DataGroup::getGroupType, req.getGroupType())
                .eq(StringUtils.isNotEmpty(req.getCode()), DataGroup::getCode, req.getCode())
                .like(StringUtils.isNotEmpty(req.getName()), DataGroup::getName, req.getName())
                .orderByAsc(DataGroup::getSortNo).orderByDesc(DataGroup::getCreatedAt);
        return this.list(lqw).stream().map(dataGroupAssembly::toDataGroupResp).collect(Collectors.toList());
    }

    /**
     * 初始化当前租户默认分组
     */
    public void initDefaultGroup(Integer bizType, String groupType) {
        long count = this.count(DataGroup.lqw()
                .eq(DataGroup::getBizType, bizType)
                .eq(StringUtils.isNotEmpty(groupType), DataGroup::getGroupType, groupType)
                .eq(DataGroup::getCode, CommonCons.DataGroup.DEFAULT_CODE));
        if (count == 0) {
            DataGroup defaultGroup = new DataGroup();
            defaultGroup.setDataCount(0L).setCode(CommonCons.DataGroup.DEFAULT_CODE)
                    .setName("默认分组").setParentId(TreeCons.ROOT_PARENT_ID)
                    .setBizType(bizType).setSortNo(-10000).setGroupType(groupType);
            this.save(defaultGroup);
        }
    }

    @Override
    public List<DataGroupTreeResp> listGroupTree(DataGroupListReq req) {
        // 初始化默认分组
        initDefaultGroup(req.getBizType(), req.getGroupType());

        LambdaQueryWrapper<DataGroup> lqw = DataGroup.lqw()
                .eq(DataGroup::getBizType, req.getBizType())
                .eq(StringUtils.isNotEmpty(req.getGroupType()), DataGroup::getGroupType, req.getGroupType())
                .orderByAsc(DataGroup::getSortNo).orderByDesc(DataGroup::getCreatedAt);
        List<DataGroupTreeResp> flatList = this.list(lqw).stream().map(dataGroupAssembly::toDataGroupTreeResp)
                .collect(Collectors.toList());

        List<DataGroupTreeResp> treeList = TreeUtils.build(flatList, TreeCons.ROOT_PARENT_ID);

        // 过滤树
        return TreeUtils.filter(treeList, (e) -> StringUtils.isEmpty(req.getName()) || e.getName().contains(req.getName()));
    }

    @Override
    public List<DataGroupResp> listChildrenGroup(Long parentId) {
        DataGroup parentGroup = this.getById(parentId);
        if (Objects.isNull(parentGroup)) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<DataGroup> lqw = DataGroup.lqw().eq(DataGroup::getBizType, parentGroup.getBizType());
        List<DataGroupTreeResp> flatList = this.list(lqw).stream().map(dataGroupAssembly::toDataGroupTreeResp)
                .collect(Collectors.toList());

        List<DataGroupTreeResp> treeList = TreeUtils.build(flatList, TreeCons.ROOT_PARENT_ID);

        // 获取查询的根节点
        AtomicReference<DataGroupTreeResp> parentTree = new AtomicReference<>();
        TreeUtils.foreachTree(treeList, (e) -> {
            if (parentTree.get() == null && e.getName().equals(parentGroup.getName())) {
                parentTree.set(e);
            }
        });

        return TreeUtils.flatTree(parentTree.get()).stream().map(dataGroupAssembly::toDataGroupResp)
                .collect(Collectors.toList());
    }

    @Override
    public DataGroupResp getGroup(Long id) {
        DataGroup entity = this.getById(id);
        return dataGroupAssembly.toDataGroupResp(entity);
    }

    @Override
    public Long saveGroup(DataGroupSaveReq req) {
        ValidationUtils.validate(validator, req);
        DataGroupBizTypeEnum.checkExistByType(req.getBizType());
        DataGroup entity = dataGroupAssembly.toDataGroup(req);
        this.save(entity);
        return entity.getId();
    }

    @Override
    public boolean updateGroup(DataGroupUpdateReq req) {
        ValidationUtils.validate(validator, req);
        DataGroup entity = dataGroupAssembly.toDataGroup(req);
        if (Objects.nonNull(req.getParentId()) && req.getParentId().compareTo(req.getId()) == 0) {
            throw new BizException("上级分组不能是自己");
        }
        LambdaUpdateWrapper<DataGroup> luw = DataGroup.luw()
                .setSql("data_count = data_count + " + req.getChangeDataCount())
                .eq(DataGroup::getId, req.getId());
        return this.update(entity, luw);
    }

    @Override
    public boolean deleteGroup(DataGroupDeleteReq req) {
        List<DataGroup> list = this.list(DataGroup.lqw().eq(DataGroup::getBizType, req.getBizType()).in(DataGroup::getId, req.getIds()));
        if (list.stream().anyMatch(e -> CommonCons.DataGroup.DEFAULT_CODE.equals(e.getCode()))) {
            throw new BizException("不能删除默认分组");
        }
        return this.removeByIds(req.getIds());
    }
}
